#include <inttypes.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"

#include "esp_wifi.h"
#include "nvs_flash.h"
#include <sys/socket.h>

#include "esp_mac.h"
#include "esp_bridge.h"
#include "esp_mesh_lite.h"

#include "BSP.h"
#include "Wireless.h"
#include "Sensor.h"


#define BRIDGE_SOFTAP_SSID              "T8-ATPS-V3.0"
#define BRIDGE_SOFTAP_PASSWORD          "bsd123456"

#define BaseTime                        1000

#define SlaveReportMsgId                100


static SlaveInfo SlaveMsg = { 0 };



extern  const char *TAG ;
/*	系统参数	*/
extern SystemParameter SysParam;
/*	系统状态	*/
extern SystemState SysState;


/**
	* @brief  无线模式时，从机在线事件处理
	* @param  None
	* @retval None
  */
static void ip_event_sta_got_ip_handler(void *arg, esp_event_base_t event_base,
                                        int32_t event_id, void *event_data)
{
   SysState.NetConnectFlag = Connect;
   ESP_LOGI(TAG, "Device Online");
}



/**
	* @brief  无线模式时，从机离线事件处理
	* @param  None
	* @retval None
  */
static void ip_event_sta_lost_ip_handler(void *arg, esp_event_base_t event_base,
                                        int32_t event_id, void *event_data)
{
   SysState.NetConnectFlag = NoConnect;
   ESP_LOGE(TAG, "Device Offline");
}



/**
	* @brief  无线主机模式时，处理从机上报信息
	* @param  None
	* @retval None
  */
static esp_err_t SlaveReportMsgHandler(uint8_t *data, uint32_t len, uint8_t **out_data, uint32_t* out_len, uint32_t seq)
{
    SlaveInfo* req = NULL;
    esp_err_t ret = ESP_FAIL;
    AtpsParameter *AtpsParam = NULL;
    float TempCali = 0;       
    float RhCali = 0; 
    float Temp;
    float RH;  		

    *out_len = 0;
    if (esp_mesh_lite_get_level() != ROOT) {
        return ESP_ERR_NOT_SUPPORTED;
    }

    // ESP_LOGI(TAG, "Receive Msg: %ld Bytes", len);

    if( len == sizeof(SlaveInfo) )
    {
        req = (SlaveInfo*)data;
    }

    
    if (req)
    {
        // ESP_LOGI(TAG, "\r\n");

        if( req->DeviceType == AtpsSa )
        {
            AtpsParam = &SysState.AtpsSaParam;
            TempCali = SysParam.AppParam.AtpsSaTempCali;
            RhCali = SysParam.AppParam.AtpsSaRhCali;

            // ESP_LOGI(TAG, "AtpsSa:");
        } 
        else if( req->DeviceType == AtpsOa )
        {
            AtpsParam = &SysState.AtpsOaParam;
            TempCali = SysParam.AppParam.AtpsOaTempCali;
            RhCali = SysParam.AppParam.AtpsOaRhCali;

            // ESP_LOGI(TAG, "AtpsOa:");
        } 
        else if( req->DeviceType == AtpsRa )
        {
            AtpsParam = &SysState.AtpsRaParam;
            TempCali = SysParam.AppParam.AtpsRaTempCali;
            RhCali = SysParam.AppParam.AtpsRaRhCali;

            // ESP_LOGI(TAG, "AtpsRa:");
        } 
        else if( req->DeviceType == AtpsMa )
        {
            AtpsParam = &SysState.AtpsMaParam;
            TempCali = SysParam.AppParam.AtpsMaTempCali;
            RhCali = SysParam.AppParam.AtpsMaRhCali;

            // ESP_LOGI(TAG, "AtpsMa:");
        } 
        else if( req->DeviceType == AtpsExa )
        {
            AtpsParam = &SysState.AtpsExaParam;
            TempCali = SysParam.AppParam.AtpsExaTempCali;
            RhCali = SysParam.AppParam.AtpsExaRhCali;

            // ESP_LOGI(TAG, "AtpsExa:");
        } 
        else if( req->DeviceType == AtpsRooma )
        {
            AtpsParam = &SysState.AtpsRoomaParam;
            TempCali = SysParam.AppParam.AtpsRoomaTempCali;
            RhCali = SysParam.AppParam.AtpsRoomaRhCali;

            // ESP_LOGI(TAG, "AtpsRooma:");
        } 
        else if( req->DeviceType == AtpsCoola )
        {
            AtpsParam = &SysState.AtpsCoolaParam;
            TempCali = SysParam.AppParam.AtpsCoolaTempCali;
            RhCali = SysParam.AppParam.AtpsCoolaRhCali;

            // ESP_LOGI(TAG, "AtpsCoola:");
        } 
        else if( req->DeviceType == AtpsHeata )
        {
            AtpsParam = &SysState.AtpsHeataParam;
            TempCali = SysParam.AppParam.AtpsHeataTempCali;
            RhCali = SysParam.AppParam.AtpsHeataRhCali;

            // ESP_LOGI(TAG, "AtpsHeata:");
        } 
        else if( req->DeviceType == AtpsHuma )
        {
            AtpsParam = &SysState.AtpsHumaParam;
            TempCali = SysParam.AppParam.AtpsHumaTempCali;
            RhCali = SysParam.AppParam.AtpsHumaRhCali;

            // ESP_LOGI(TAG, "AtpsHuma:");
        } 
        else if( req->DeviceType == AtpsPre )
        {
            AtpsParam = &SysState.AtpsPreParam;
            TempCali = SysParam.AppParam.AtpsPreTempCali;
            RhCali = SysParam.AppParam.AtpsPreRhCali;

            // ESP_LOGI(TAG, "AtpsPre:");
        } 
        else if( req->DeviceType == AtpsRot )
        {
            AtpsParam = &SysState.AtpsRotParam;
            TempCali = SysParam.AppParam.AtpsRotTempCali;
            RhCali = SysParam.AppParam.AtpsRotRhCali;

            // ESP_LOGI(TAG, "AtpsRot:");
        } 


        RH = req->Rh + RhCali;
        Temp = req->Temp + TempCali;

        AtpsParam->TDB = Temp;
        AtpsParam->RH = RH;
        AtpsParam->TDP = calc_dew_point_temp(Temp, RH);
        AtpsParam->TWB = calc_wet_bulb_temp(Temp, RH, SysParam.AppParam.Atmosphere);
        AtpsParam->HR = calc_humidity_ratio(Temp, RH, SysParam.AppParam.Atmosphere);
        AtpsParam->H = calc_enthalpy(Temp, RH, SysParam.AppParam.Atmosphere);

        AtpsParam->Rssi = req->Rssi;

        AtpsParam->SensorFault = req->SensorFault;
        AtpsParam->SensorFaultCnt = req->SensorFaultCnt;
       
        AtpsParam->CommTimeoutCnt = 0;
        AtpsParam->CommFault = NoFault;

        // ESP_LOGI(TAG, "信号强度: %d  干球温度: %0.2f  相对湿度: %0.2f  露点温度: %0.2f  湿球温度: %0.2f  含湿量: %0.2f  焓值: %0.2f", 
        //         AtpsParam->Rssi, AtpsParam->TDB, AtpsParam->RH,  AtpsParam->TDP, AtpsParam->TWB, AtpsParam->HR, AtpsParam->H);

        // ESP_LOGI(TAG, "\r\n");

        ret = ESP_OK;
    }

    return ret;
}



static const esp_mesh_lite_raw_msg_action_t raw_msgs_action[] = {
    {SlaveReportMsgId, 0, SlaveReportMsgHandler},
    {0, 0, NULL}
};




/**
	* @brief  初始化Wifi
	* @param  None
	* @retval None
  */
static void WiFiInit(void)
{
    // Station
    wifi_config_t wifi_config;
    wifi_config_t wifi_softap_config = { 0 };
    memset(&wifi_config, 0x0, sizeof(wifi_config_t));
    esp_bridge_wifi_set_config(WIFI_IF_STA, &wifi_config);

    // Softap
    memset( wifi_softap_config.ap.ssid, 0, sizeof( wifi_softap_config.ap.ssid ) );
    memcpy( wifi_softap_config.ap.ssid, BRIDGE_SOFTAP_SSID, strlen( BRIDGE_SOFTAP_SSID ) );

    memset( wifi_softap_config.ap.password, 0, sizeof( wifi_softap_config.ap.password ) );
    memcpy( wifi_softap_config.ap.password, BRIDGE_SOFTAP_PASSWORD, strlen( BRIDGE_SOFTAP_PASSWORD ) );

    wifi_softap_config.ap.channel = SysParam.WorkParam.NetChannel;
    wifi_softap_config.ap.ssid_hidden = 1;      //隐藏wifi ssid

    esp_bridge_wifi_set_config(WIFI_IF_AP, &wifi_softap_config);
}




/**
	* @brief  初始化无线通信
	* @param  None
	* @retval None
  */
void WirelessInit( void )
{
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    esp_bridge_create_all_netif();

    WiFiInit( );

    esp_mesh_lite_config_t mesh_lite_config = ESP_MESH_LITE_DEFAULT_INIT(); 
    mesh_lite_config.join_mesh_ignore_router_status = true;
    mesh_lite_config.softap_ssid = (char *)BRIDGE_SOFTAP_SSID;
    mesh_lite_config.softap_password = (char *)BRIDGE_SOFTAP_PASSWORD;

    if( SysParam.WorkParam.WorkMode == WirelessMaster )
    {
        mesh_lite_config.join_mesh_without_configured_wifi = false;
    }
    else
    {
        mesh_lite_config.join_mesh_without_configured_wifi = true;
    }

    esp_mesh_lite_init(&mesh_lite_config);

    esp_mesh_lite_set_mesh_id(SysParam.WorkParam.NetId, true );

    if( SysParam.WorkParam.WorkMode == WirelessMaster )
    {
        esp_mesh_lite_set_allowed_level(1);
    }
    else
    {
        esp_mesh_lite_set_disallowed_level(1);
    }

    esp_mesh_lite_start();
    
    if( SysParam.WorkParam.WorkMode == WirelessSlave )
    {
        ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_sta_got_ip_handler, NULL, NULL));
        ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_LOST_IP, &ip_event_sta_lost_ip_handler, NULL, NULL));
    }
    else
    {
        ESP_ERROR_CHECK( esp_mesh_lite_raw_msg_action_list_register(raw_msgs_action) );
    }
}




/**
	* @brief  无线从机通信处理
	* @param  None
	* @retval None
  */
 static void WirelessSlaveProcess( void )
 {
    static uint8_t state = 0;
    static uint16_t time_interval = 0;
    static uint16_t device_type = 0;
    static uint8_t fault_cnt = 0;
    static uint32_t time_cnt = 0;
    static AtpsParameter *AtpsParam = NULL;
    esp_mesh_lite_msg_config_t config ={ 0 };
    wifi_ap_record_t ap_info  = {0};
    esp_err_t err = 0;

    switch( state )
    {
        case 0:
        {
            device_type = SysParam.WorkParam.DeviceType;

            if( device_type == AtpsSa )
            {
                AtpsParam = &SysState.AtpsSaParam;
            }
            else if( device_type == AtpsOa )
            {
                AtpsParam = &SysState.AtpsOaParam;
            }
            else if( device_type == AtpsRa )
            {
                AtpsParam = &SysState.AtpsRaParam;
            }
            else if( device_type == AtpsMa )
            {
                AtpsParam = &SysState.AtpsMaParam;
            }
            else if( device_type == AtpsExa )
            {
                AtpsParam = &SysState.AtpsExaParam;
            }
            else if( device_type == AtpsRooma )
            {
                AtpsParam = &SysState.AtpsRoomaParam;
            }
            else if( device_type == AtpsCoola )
            {
                AtpsParam = &SysState.AtpsCoolaParam;
            }
            else if( device_type == AtpsHeata )
            {
                AtpsParam = &SysState.AtpsHeataParam;
            }
            else if( device_type == AtpsHuma )
            {
                AtpsParam = &SysState.AtpsHumaParam;
            }
            else if( device_type == AtpsPre )
            {
                AtpsParam = &SysState.AtpsPreParam;
            }
            else if( device_type == AtpsRot )
            {
                AtpsParam = &SysState.AtpsRotParam;
            }

            time_interval = BaseTime + device_type * 100;

            fault_cnt = 0;
            time_cnt = 0;

            state = 1;
        }
        break;

        case 1:
        {
            //在线
            if( SysState.NetConnectFlag == Connect )
            {
                vTaskDelay( 100 / portTICK_PERIOD_MS ); 

                time_cnt += 100;
                if( time_cnt >= time_interval )
                {
                    time_cnt = 0;

                    esp_wifi_sta_get_ap_info(&ap_info);

                    SlaveMsg.DeviceType = device_type;
                    SlaveMsg.SensorFault = AtpsParam->SensorFault;
                    SlaveMsg.SensorFaultCnt = AtpsParam->SensorFaultCnt;
                    SlaveMsg.Temp =  AtpsParam->TDB;
                    SlaveMsg.Rh =  AtpsParam->RH;

                    if( ap_info.rssi != 0 )
                    {
                        SlaveMsg.Rssi = ap_info.rssi;
                        AtpsParam->Rssi = ap_info.rssi;
                    }
                    else 
                    {
                        SlaveMsg.Rssi = -120;
                        AtpsParam->Rssi = -120;
                    }

                    config.raw_msg.msg_id = SlaveReportMsgId;
                    config.raw_msg.expect_resp_msg_id = 0;
                    config.raw_msg.max_retry = 1;
                    config.raw_msg.data = (uint8_t *)&SlaveMsg;
                    config.raw_msg.size = sizeof( SlaveMsg );
                    config.raw_msg.raw_resend = esp_mesh_lite_send_raw_msg_to_root;

                    err = esp_mesh_lite_send_msg(ESP_MESH_LITE_RAW_MSG, &config);
                    if( err == ESP_OK )     //从机消息发送成功
                    {
                        fault_cnt = 0;
                        AtpsParam->CommFault = NoFault;
                    }
                    else 
                    {
                        fault_cnt++;
                        if( fault_cnt >= 10 )   //从机连续发送消息失败次数大于10此，判定通讯故障
                        {
                            fault_cnt = 0;

                            if(  AtpsParam->CommFault == NoFault )
                            {
                                AtpsParam->CommFault = Fault;
                                AtpsParam->CommFaultCnt++;
                            }

                        }
                    }

                    // ESP_LOGI(TAG, "fault_cnt: %d  CommFaultCnt: %ld", fault_cnt, AtpsParam->CommFaultCnt);
                }
            }
            //离线
            else 
            {
                fault_cnt = 0;

                if( AtpsParam->CommFault == NoFault )
                {
                    AtpsParam->CommFault = Fault;
                    AtpsParam->CommFaultCnt++;

                    AtpsParam->Rssi = -120;
                }

                vTaskDelay( 300 / portTICK_PERIOD_MS ); 
            }
        }
        break;
    }
 }




 /**
	* @brief  无线主机通信处理
	* @param  None
	* @retval None
  */
 static void WirelessMasterProcess( void )
 {
    static uint8_t state = 0;
    static AtpsParameter *AtpsParam = NULL;
    static uint16_t device_type = 0;

    switch( state )
    {
        case 0:
        {
            device_type = SysParam.WorkParam.DeviceType;

            if( device_type == AtpsSa )
            {
                AtpsParam = &SysState.AtpsSaParam;
            }
            else if( device_type == AtpsOa )
            {
                AtpsParam = &SysState.AtpsOaParam;
            }
            else if( device_type == AtpsRa )
            {
                AtpsParam = &SysState.AtpsRaParam;
            }
            else if( device_type == AtpsMa )
            {
                AtpsParam = &SysState.AtpsMaParam;
            }
            else if( device_type == AtpsExa )
            {
                AtpsParam = &SysState.AtpsExaParam;
            }
            else if( device_type == AtpsRooma )
            {
                AtpsParam = &SysState.AtpsRoomaParam;
            }
            else if( device_type == AtpsCoola )
            {
                AtpsParam = &SysState.AtpsCoolaParam;
            }
            else if( device_type == AtpsHeata )
            {
                AtpsParam = &SysState.AtpsHeataParam;
            }
            else if( device_type == AtpsHuma )
            {
                AtpsParam = &SysState.AtpsHumaParam;
            }
            else if( device_type == AtpsPre )
            {
                AtpsParam = &SysState.AtpsPreParam;
            }
            else if( device_type == AtpsRot )
            {
                AtpsParam = &SysState.AtpsRotParam;
            }

            AtpsParam->CommFault = NoFault;
            AtpsParam->CommFaultCnt = 0;
            AtpsParam->Rssi = 0;

            state = 1;
        }
        break;

        case 1:
        {
            if( (SysState.AtpsSaParam.CommFault == NoFault) && ( device_type != AtpsSa ) )
            {
                    SysState.AtpsSaParam.CommTimeoutCnt++;

                    if( SysState.AtpsSaParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsSaParam.CommTimeoutCnt = 0;
                        SysState.AtpsSaParam.CommFault = Fault;
                        SysState.AtpsSaParam.CommFaultCnt++;
                        SysState.AtpsSaParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsOaParam.CommFault == NoFault) && ( device_type != AtpsOa ) )
            {
                    SysState.AtpsOaParam.CommTimeoutCnt++;

                    if( SysState.AtpsOaParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsOaParam.CommTimeoutCnt = 0;
                        SysState.AtpsOaParam.CommFault = Fault;
                        SysState.AtpsOaParam.CommFaultCnt++;
                        SysState.AtpsOaParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsRaParam.CommFault == NoFault) && ( device_type != AtpsRa ) )
            {
                    SysState.AtpsRaParam.CommTimeoutCnt++;

                    if( SysState.AtpsRaParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsRaParam.CommTimeoutCnt = 0;
                        SysState.AtpsRaParam.CommFault = Fault;
                        SysState.AtpsRaParam.CommFaultCnt++;
                        SysState.AtpsRaParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsMaParam.CommFault == NoFault) && ( device_type != AtpsMa ) )
            {
                    SysState.AtpsMaParam.CommTimeoutCnt++;

                    if( SysState.AtpsMaParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsMaParam.CommTimeoutCnt = 0;
                        SysState.AtpsMaParam.CommFault = Fault;
                        SysState.AtpsMaParam.CommFaultCnt++;
                        SysState.AtpsMaParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsExaParam.CommFault == NoFault) && ( device_type != AtpsExa ) )
            {
                    SysState.AtpsExaParam.CommTimeoutCnt++;

                    if( SysState.AtpsExaParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsExaParam.CommTimeoutCnt = 0;
                        SysState.AtpsExaParam.CommFault = Fault;
                        SysState.AtpsExaParam.CommFaultCnt++;
                        SysState.AtpsExaParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsRoomaParam.CommFault == NoFault) && ( device_type != AtpsRooma ) )
            {
                    SysState.AtpsRoomaParam.CommTimeoutCnt++;

                    if( SysState.AtpsRoomaParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsRoomaParam.CommTimeoutCnt = 0;
                        SysState.AtpsRoomaParam.CommFault = Fault;
                        SysState.AtpsRoomaParam.CommFaultCnt++;
                        SysState.AtpsRoomaParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsCoolaParam.CommFault == NoFault) && ( device_type != AtpsCoola ) )
            {
                    SysState.AtpsCoolaParam.CommTimeoutCnt++;

                    if( SysState.AtpsCoolaParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsCoolaParam.CommTimeoutCnt = 0;
                        SysState.AtpsCoolaParam.CommFault = Fault;
                        SysState.AtpsCoolaParam.CommFaultCnt++;
                        SysState.AtpsCoolaParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsHeataParam.CommFault == NoFault) && ( device_type != AtpsHeata ) )
            {
                    SysState.AtpsHeataParam.CommTimeoutCnt++;

                    if( SysState.AtpsHeataParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsHeataParam.CommTimeoutCnt = 0;
                        SysState.AtpsHeataParam.CommFault = Fault;
                        SysState.AtpsHeataParam.CommFaultCnt++;
                        SysState.AtpsHeataParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsHumaParam.CommFault == NoFault) && ( device_type != AtpsHuma ) )
            {
                    SysState.AtpsHumaParam.CommTimeoutCnt++;

                    if( SysState.AtpsHumaParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsHumaParam.CommTimeoutCnt = 0;
                        SysState.AtpsHumaParam.CommFault = Fault;
                        SysState.AtpsHumaParam.CommFaultCnt++;
                        SysState.AtpsHumaParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsPreParam.CommFault == NoFault) && ( device_type != AtpsPre ) )
            {
                    SysState.AtpsPreParam.CommTimeoutCnt++;

                    if( SysState.AtpsPreParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsPreParam.CommTimeoutCnt = 0;
                        SysState.AtpsPreParam.CommFault = Fault;
                        SysState.AtpsPreParam.CommFaultCnt++;
                        SysState.AtpsPreParam.Rssi = -120;
                    }
            }

            if( (SysState.AtpsRotParam.CommFault == NoFault) && ( device_type != AtpsRot ) )
            {
                    SysState.AtpsRotParam.CommTimeoutCnt++;

                    if( SysState.AtpsRotParam.CommTimeoutCnt >= 40 )
                    {
                        SysState.AtpsRotParam.CommTimeoutCnt = 0;
                        SysState.AtpsRotParam.CommFault = Fault;
                        SysState.AtpsRotParam.CommFaultCnt++;
                        SysState.AtpsRotParam.Rssi = -120;
                    }
            }

            vTaskDelay( 1000 / portTICK_PERIOD_MS ); 
        }
        break;
    }
 }





/**
	* @brief  无线通信处理
	* @param  None
	* @retval None
  */
 void WirelessProcess( void )
 {
    static uint8_t state = 0;

    switch( state )
    {
        case 0:
        {
            if( SysParam.WorkParam.WorkMode == WirelessMaster )
            {
                state = 2;
            }
            else 
            {
                state = 1;
            }
        }
        break;

        case 1:
        {
            WirelessSlaveProcess( );        //无线从机通信处理
        }
        break;

        case 2:
        {
            WirelessMasterProcess( );       //无线主机通信处理
        }
        break;
    }
 }







